package facilitator;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Random;

import core.CalculationException;
import core.DmuList;
import core.Optimizer;
import core.PdmOptimization;

import util.BinaryCombinationsIterator;
import util.Util;

public class Tool {
	public static Random randomizer;
	public static Hashtable<Integer, String> erpVendors;
    public static int roundingPrecision = 5;
	
	static{
		randomizer = new Random();
		erpVendors = new Hashtable<Integer, String>();
		erpVendors.put(0, "ERP Total");
		erpVendors.put(1, "InternetCorp");
		erpVendors.put(2, "Business Software Ltd");
	}
	public static double[] randomizeWeights(double[] weights){
		double[] temp = weights.clone();
		for(int i=0;i<weights.length;i++){
			//NOISE1: temp[i] = weights[i] + randomizer.nextDouble()/1000-0.5/1000;
			//NOISE2: temp[i] = weights[i] + randomizer.nextDouble()/100-0.5/100;
			//NOISE3: temp[i] = weights[i] + randomizer.nextDouble()/10-0.5/10;
			//NOISE4: NOISE1 + NOISE1(criteria.amount)
			temp[i] = addRandom(weights[i]);
		}
		return temp;
	}
	public static double addRandom(double in)
	{
		return in + randomizer.nextDouble()/10-0.5/10;
	}
	public static List<PdmOptimization> getBestObjectiveDirections(DmuList dmuList, int objectiveDmu, double[] urmWeights, double alpha) throws CalculationException{
		BinaryCombinationsIterator it = new BinaryCombinationsIterator(dmuList.outputSize);
		List<PdmOptimization> optima = new ArrayList<PdmOptimization>();
		double currObj = 0.0d;
		boolean entry = true;
		PdmOptimization currOptimization;
		while(it.hasNext()){
			currOptimization = new PdmOptimization(dmuList, objectiveDmu, alpha,urmWeights, it.next());
			Optimizer.calculatePdm(currOptimization);
            double tempObj = Util.roundUp(currOptimization.getOptimizationObjective(), roundingPrecision);
			if(tempObj  > currObj){
				optima.clear();
				currObj = tempObj;
			}
			if(tempObj == currObj){
				entry = true;
				for(int l = 0;l < optima.size();l++){
					if(Tool.getVectorDiff(optima.get(l), currOptimization) == 0){
						entry = false;
					}
				}
				if(entry){
					optima.add(currOptimization);
				}
				//Util.log(Arrays.toString(currOptimization.getOptimizationDirections()) + ";" + currOptimization.toString());
			}
		}
		for(PdmOptimization r:optima){
			//Util.print(r.getOptimizationObjective() + " :: " + Arrays.toString(r.getOptimizationWeights()));
		}
		return optima;
	}
    public static int getDifferentOptimizers(List<PdmOptimization> list) throws CalculationException{
        List<PdmOptimization> vectors = new ArrayList<PdmOptimization>();
        vectors.add(list.get(0));

        boolean niew = true;
        for(PdmOptimization left:list){
            niew = true;
            for(PdmOptimization right:vectors){
                if(Tool.getVectorDeviations(left, right)==0){
                    niew = false;
                }
            }
            if(niew){
                vectors.add(left);
            }
        }
        return vectors.size();
    }
    private static double getVectorDeviations(PdmOptimization left, PdmOptimization right) throws CalculationException{
		double tempDiff = 0d;
		for(int z = 0;z<left.getDmuList().outputSize;z++){
			tempDiff+=
				Math.abs(Util.roundUp(left.getOptimizationWeight(z), roundingPrecision) - Util.roundUp(right.getOptimizationWeight(z),roundingPrecision));
		}
		return tempDiff;
	}
	public static ArrayList<Double> getInternalVectorDiffs(List<PdmOptimization> list) throws CalculationException{
		ArrayList<Double> diffs = new ArrayList<Double>();		
		double tempDiff = 0d;
		PdmOptimization left;
		PdmOptimization right;
		for(int a = 0;a<list.size();a++){
			left = list.get(a);
			//output logging
			/*Util.log("Optimal Vars " + a + " " + Arrays.toString(left.getOptimizationDirections()));
			for(int o=0;o<left.getDmuList().outputSize;o++){
				try{
					Util.log(o +": " + left.getOptimizationWeight(o)/left.getOptimizationWeight(0));
				}
				catch(Exception e){
					
				}
			}*/
			//Util.log("------------");
			for (int b = 0;b<list.size();b++){
				if(a!=b){
					right = list.get(b);
					//Util.print("compare");
					tempDiff = 0d;
					for(int z = 0;z<left.getDmuList().outputSize;z++){
						tempDiff+= 
							Math.abs(left.getOptimizationWeight(z) - right.getOptimizationWeight(z));
						//Util.print(left.dmuList.get(left.getOptimizationInput().objectiveDmu).criteria.get(z).weighting + " - " +
						//		right.dmuList.get(right.getOptimizationInput().objectiveDmu).criteria.get(z).weighting);		
						//Util.print(tempDiff);
					}
					diffs.add(tempDiff);
				}
			}
		}
		//Collections.sort(diffs);
		return diffs;
	}
	private static double getVectorDiff(PdmOptimization left, PdmOptimization right) throws CalculationException{
		double tempDiff = 0d;
		for(int z = 0;z<left.getDmuList().outputSize;z++){
			tempDiff+= 
				Math.abs(Util.roundUp(left.getOptimizationWeight(z), roundingPrecision) - Util.roundUp(right.getOptimizationWeight(z),roundingPrecision));
		}
		return tempDiff;
	}
	public static ArrayList<Double> getDiffsToExternalVector(List<PdmOptimization> list, PdmOptimization r) throws CalculationException{
		ArrayList<Double> diffs = new ArrayList<Double>();		
		double tempDiff = 0d;
		PdmOptimization left;
		PdmOptimization right = r;
		
		Util.log("Heuristik Vars ");
		for(int o=0;o<right.getDmuList().outputSize;o++){
			Util.log(o +": " + right.getOptimizationWeight(o));
		}
		Util.log("------------");
		
		for(int a = 0;a<list.size();a++){
			left = list.get(a);
			tempDiff = 0d;
			for(int z = 0;z<left.getDmuList().outputSize;z++){
				tempDiff+=
				Math.abs(left.getOptimizationWeight(z) - right.getOptimizationWeight(z));
			}
			diffs.add(tempDiff);
		}
		Collections.sort(diffs);
		return diffs;
	}
	public static double[] getRelWeights(double[] absUrmWeights) {
		double sum = 0;
		for(double x:absUrmWeights){
			sum+=x;
		}
		for(int x = 0;x < absUrmWeights.length;x++){
			absUrmWeights[x] = Util.truncate(absUrmWeights[x]/sum*100,2);
		}
		return absUrmWeights;
	}
	public static double[] getAbsWeights(double[] relUrmWeights) {
		double sum = 0;
		for(double x:relUrmWeights){
			sum+=x;
		}
		for(int x = 0;x < relUrmWeights.length;x++){
			relUrmWeights[x] = relUrmWeights[x]*sum/100;
		}
		return relUrmWeights;
	}
}
